//
// Created by 抑~风 on 2022/11/20.
//


#include<iostream>
#include<unordered_set>
#include<fstream>
#include"regexp.h"

using namespace std;
using namespace CWJ;

void show(RegexParser::ASTNodePtr root, string text) {
    if (root == nullptr) return;
    auto childs = root->getChilds();
    auto s = root->getContext();
    cout << text << (unsigned int) root->getType() << ":" << " from " << s.getFrom() << " to " << s.getTo() << " min: "
         << root->getMinTime() << " max: " << root->getMaxTime() << endl;
    for (auto &a : childs) {
        show(dynamic_pointer_cast<RegexParser::ASTNode>(a), text + "    ");
    }
}

void showNfaNode(NfaGraph::NfaNodePtr root) {
    string text = "    ";
    cout << root->getUid() << " " << root->isAc1() << endl;
    for (auto &o : root->getVers()) {
        cout << text << o.first->getUid() << endl;
    }
}

unordered_set<NfaGraph::NfaNodePtr> st;

void showGraph(NfaGraph::NfaNodePtr root) {
    cout << "---" << endl;
    if (st.count(root)) return;
    st.insert(root);
    string text = "    ";
    showNfaNode(root);
    for (auto &o : root->getVers()) {
        showGraph(o.first);
    }
}

void test_regex() {

    ASTNode<string, string> s;
    cout << s.getType() << endl;

    cout << "Hello compiler" << endl;

//    string script = "double|int | [A-Z]*[abA-Z0-9]+a?";
//    string script = "[a-zA-Z0-9_]*";
    string script = "\\-?[0-9]*";

    RegexpLever regexpLever;
    RegexParser regexParser;

    auto list = regexpLever.tokenize(script);

    auto tree = regexParser.parse(list);

    cout << tree << endl;

    for (auto &a : list) {
        cout << static_cast<unsigned int>(a.getType()) << ": " << a.getConText() << endl;
    }
    show(tree, "");

    NfaGraph g;

    g.regexAST2nfaGraph(tree);

    showGraph(g.getStartState());


}

void test(string name, string script, string rulePath) {
    cout << "-------------------- " << name << " ---------------------" << endl;
    cout << "script:" << endl << " " << script << endl;
    cout << "tokens:" << endl;
    CWJLever lever;
    lever.readRule(rulePath);
    const auto &tokens = lever.tokenize(script);
//    for(const auto & t : tokens){
//        cout<<t.getType()<<" "<<t.getConText()<<endl;
//    }
    for (int i = 0; i < tokens.size(); i++) {
        const auto &t = tokens[i];
        cout<<t.getType()<<" "<<t.getConText()<<"\t\t\t\t\t\t\t\t\t\t\t\t";
        if((i+1)%3 == 0)   cout<<endl;
    }
    cout<<endl<<"-------------------------------------------------------"<<endl;

}

string readScript4() {
    ifstream in("D:\\myCppWorkPlace\\cwj_compiler\\src\\resource\\lab1\\script4_code.txt");
    string buf, res;
    while (in >> buf) res += buf;
    return res;
}

void test_script1() {
    string name = "test_script1";
    string script = "begin\n"
                    "\tbegin\n"
                    "\t\n"
                    "\t\tbegin \n"
                    "\t\t a:=1\n"
                    " \t\tend;\n"
                    " \t\t\n"
                    " \t  begin \n"
                    "\t\t b:=1\n"
                    "    end;\n"
                    "    q:=10\n"
                    "\tend;\n"
                    "\t\n"
                    "\tx:=9;\n"
                    "\ty:=11;\n"
                    "\tz:=12\n"
                    "end\n"
                    "#~";

    string path = "D:\\myCppWorkPlace\\cwj_compiler\\src\\resource\\lab1\\script1_2_rule.txt";
    test(name, script, path);
}

void test_script2() {
    string name = "test_script2";
    string script = "else begin \t\t\n"
                    "       \tA:=A+B+C;\n"
                    "      \tC:=A+2;\n"
                    "while A<C and B<D do\n"
                    "            while A>B do \n"
                    "               if M=N then C:=D\n"
                    "             else while A<=D do\n"
                    "                 A:=D\n"
                    "    \tend#~";

    string path = "D:\\myCppWorkPlace\\cwj_compiler\\src\\resource\\lab1\\script1_2_rule.txt";
    test(name, script, path);
}

void test_script3() {
    string name = "test_script3";
    string script = "end begin\n"
                    "    nums[] = new int ();\n"
                    "    byte = new double();\n"
                    "    _num23 = 1234;\n"
                    "    n23m = _num23;\n"
                    "end";

    string path = "D:\\myCppWorkPlace\\cwj_compiler\\src\\resource\\lab1\\script3_rule.txt";
    test(name, script, path);
}

void test_script4() {
    string name = "test_script4";
    string script = readScript4();

    string path = "D:\\myCppWorkPlace\\cwj_compiler\\src\\resource\\lab1\\script4_rule.txt";
    test(name, script, path);
}


int main() {


    test_script1();
    test_script2();
    test_script3();
    test_script4();


    return 0;
}


